package net.wang.totakecodenotes.wechatofficaccounts.weixin;

import net.wang.totakecodenotes.wechatofficaccounts.domain.JSAPITicket;
import net.wang.totakecodenotes.wechatofficaccounts.domain.WeiXinAccessToken;
import net.wang.totakecodenotes.wechatofficaccounts.domain.WeiXinUserInfo;
import net.wang.totakecodenotes.wechatofficaccounts.repository.JSAPITicketRepo;
import net.wang.totakecodenotes.wechatofficaccounts.repository.WeiXinAccessTokenRepo;
import net.wang.totakecodenotes.wechatofficaccounts.repository.WeiXinUserInfoRepo;
import net.wang.totakecodenotes.wechatofficaccounts.utils.FileUtils;
import net.wang.totakecodenotes.wechatofficaccounts.utils.HttpUtils;
import net.wang.totakecodenotes.wechatofficaccounts.utils.JSAPIUtils;
import net.wang.totakecodenotes.wechatofficaccounts.utils.JSONUtils;
import org.apache.log4j.LogManager;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.net.URLEncoder;
import java.util.Date;
import java.util.List;
import java.util.Map;

/**
 *
 */
@Service
public class WeiXinService {

    private final Logger logger = LogManager.getLogger(this.getClass());
    @Resource
    private WeiXinUserInfoRepo weiXinUserInfoRepo;
    @Autowired
    private WinXinConfig WIN_XIN_CONFIG;
    @Resource
    private WeiXinAccessTokenRepo weiXinAccessTokenRepo;
    @Resource
    private JSAPITicketRepo jsapiTicketRepo;

    /**
     * 跳转至微信网页授权，获取code
     * <p>
     * code 作为重定向地址的路径中增加的参数，在重定向的controller里获取，用于获取 网页授权的access_token和openId。code有效次数为1
     * </p>
     *
     * @param redirect 重定向的地址
     * @param response 相应
     * @return
     */
    public String getCode(String redirect, HttpServletResponse response) {
        try {
            String codeUrl = "https://open.weixin.qq.com/connect/oauth2/authorize?appid=" + WIN_XIN_CONFIG.getAppId() + "&redirect_uri=" + URLEncoder.encode(redirect, "UTF-8") + "&response_type=code&scope=snsapi_userinfo&state=to_take_code_notes#wechat_redirect";
            logger.info(codeUrl);
            response.sendRedirect(codeUrl);
        } catch (IOException e) {
            e.printStackTrace();
        }

        return redirect;

    }

    /**
     * 根据code获取网页授权的access_token和openId
     *
     * @param code
     * @return
     * @throws Exception
     */
    public Authorize getAccessTokenAndOpenId(String code) throws Exception {
        String accessTokenUrl = "https://api.weixin.qq.com/sns/oauth2/access_token?appid="
                + WIN_XIN_CONFIG.getAppId()
                + "&secret=" + WIN_XIN_CONFIG.getAppSecret()
                + "&code=" + code
                + "&grant_type=authorization_code";
        return JSONUtils.getEntity(HttpUtils.getJSONString(accessTokenUrl), Authorize.class);
    }

    /**
     * 获取基础令牌 access_token
     *
     * @return
     * @throws Exception
     */
    public WeiXinAccessToken getAccessToken() throws Exception {
        WeiXinAccessToken accessToken = weiXinAccessTokenRepo.findOne(1);
        if (accessToken == null || accessToken.getEffectAt().before(new Date())) {
            String accessTokenUrl = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid="
                    + WIN_XIN_CONFIG.getAppId()
                    + "&secret=" + WIN_XIN_CONFIG.getAppSecret();
            logger.info("从微信服务器获取access_token");
            WeiXinAccessToken token = JSONUtils.getEntity(HttpUtils.getJSONString(accessTokenUrl), WeiXinAccessToken.class);
            token.setId(1);
            return weiXinAccessTokenRepo.save(token);
        } else {
            logger.info("从本地数据库获取access_token");
            return accessToken;
        }

    }

    /**
     * 根据网页授权的 access_token和openId 获取微信用户信息
     *
     * @param authorize 封装了 access_token和openId等的对象
     * @return
     * @throws Exception
     */
    public WeiXinUserInfo getUserInfo(Authorize authorize) throws Exception {
        logger.info("获取微信用户信息 authorize :" + authorize);
        List<WeiXinUserInfo> infos = weiXinUserInfoRepo.findByOpenId(authorize.getOpenId());
        if (infos.isEmpty()) {
            String userInfoUrl = "https://api.weixin.qq.com/sns/userinfo?access_token="
                    + authorize.getAccessToken() + "&openid="
                    + authorize.getOpenId() + "&lang=zh_CN";
            return weiXinUserInfoRepo.save(JSONUtils.getEntity(HttpUtils.getJSONString(userInfoUrl), WeiXinUserInfo.class));
        } else {
            return infos.get(0);
        }
    }

    /**
     * 获取 调用微信JS接口的临时票据
     *
     * @return
     * @throws Exception
     */
    public JSAPITicket getTicket() throws Exception {
        JSAPITicket ticket = jsapiTicketRepo.findOne(1);
        if (ticket == null || ticket.getEffectAt().before(new Date())) {
            logger.info("从微信服务器获取微信JS接口的临时票据");
            String url = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=" + getAccessToken().getAccessToken() + "&type=jsapi";
            JSAPITicket jsapiTicket = JSONUtils.getEntity(HttpUtils.getJSONString(url), JSAPITicket.class);
            jsapiTicket.setId(1);
            return jsapiTicketRepo.save(jsapiTicket);
        } else {
            logger.info("从本地数据库获取微信JS接口的临时票据");
            return ticket;
        }
    }

    /**
     * 获取微信配置信息
     *
     * @param url 地址 包含参数或者没有参数
     * @return
     * @throws Exception
     */
    public Map<String, String> getWeiXinJSConfig(String url) throws Exception {
        Map<String, String> signature = JSAPIUtils.sign(getTicket().getTicket(), url);
        signature.put("appId", WIN_XIN_CONFIG.getAppId());
        logger.info("获取微信配置信息 :" + signature);
        return signature;
    }

    public Object saveWeiXinMedia(String mediaId, String type, Date createdAt) throws Exception {

        String requestUrl = "http://file.api.weixin.qq.com/cgi-bin/media/get?access_token=" + getAccessToken().getAccessToken() + "&media_id=" + mediaId;
        return FileUtils.getWeiXinFile(mediaId, requestUrl);
    }


}
